import type { Request, Response } from 'express';

import { Types } from 'mongoose';
import { z } from 'zod';

import { AppModel, IApp } from '../../../models/app';
import { RepoModel } from '../../../models/repo';
import Resp from '../../../utils/response';
import { createAppDirectory } from '../utils';

// 参数校验规则
export const validator = z.object({
  name: z
    .string({
      invalid_type_error: '应用名称必须是字符串',
      required_error: '应用名称不能为空',
    })
    .min(1, '应用名称不能为空')
    .max(100, '应用名称不能超过100个字符')
    .transform(val => val?.trim()),
  remark: z
    .string({
      invalid_type_error: '应用描述必须是字符串',
    })
    .max(500, '描述不能超过500个字符')
    .transform(val => val?.trim())
    .default(''),
  repository: z
    .array(
      z
        .string({
          invalid_type_error: '仓库ID必须是字符串',
          required_error: '仓库ID不能为空',
        })
        .min(1, '仓库ID不能为空'),
      { invalid_type_error: '仓库ID列表必须是数组', required_error: '仓库ID列表不能为空' },
    )
    .min(1, '至少需要选择一个仓库')
    .default([]),
});

// 创建应用 api
export const api = async (req: Request, res: Response): Promise<Response> => {
  try {
    const { name, remark, repository } = req.body as z.infer<typeof validator>;

    // 检查应用是否已存在
    const existingApp = await AppModel.findOne({ name });
    if (existingApp) {
      return Resp.error(res, 400, `应用 ${name} 已存在`);
    }

    // 检查所有仓库ID是否存在
    const repos = await RepoModel.find({ _id: { $in: repository } });
    if (repos.length !== repository.length) {
      const foundIds = repos.map(repo => repo._id.toString());
      const invalidIds = repository.filter(id => !foundIds.includes(id));
      return Resp.error(res, 400, `以下仓库ID不存在：${invalidIds.join(', ')}`);
    }
    for (const id of repository) {
      if (!Types.ObjectId.isValid(id)) {
        return Resp.error(res, 400, `仓库ID ${id} 不是合法的 ObjectId`);
      }
    }
    // 构建应用数据
    const appData: IApp = {
      name,
      remark,
      // eslint-disable-next-line @typescript-eslint/ban-ts-comment
      // @ts-expect-error
      repository,
      scriptGroup: [],
    };

    // 保存应用数据到数据库
    const app = new AppModel(appData);
    const result = await app.save();

    // 异步创建应用文件夹（不影响响应）
    createAppDirectory(result._id.toString()).catch(error => {
      console.error(`应用 ${result._id} 文件夹创建失败:`, error);
    });

    console.log(`应用创建成功: ${result.name} (ID: ${result._id})`);
    return Resp.success(res, result, '应用创建成功');
  } catch (error) {
    console.error(error);
    // 捕获并处理异常，按错误类型返回合适响应
    return Resp.catch(res, error);
  }
};
